#pragma once
namespace graph
{
   namespace algorithm
   {
      struct astar_vertex_data_t
      {
          static const char NOT_VISITED = 0;
          static const char PROCESSED = 1;
          static const char VISITED = 2;
          char color_;
          lat_lon_t distance_;
          vertex_id_t predecessor_;
          astar_vertex_data_t()
            :  distance_(MAX_FLOAT)
            ,  color_(astar_vertex_data_t::NOT_VISITED)
          {}
      };

      struct astar_initializer_t;

      //the astar search algorithm
      template<mode_e mode, directional_e directional>
      struct astar_search_t
      {  
         astar_search_t(graph_view_ptr_t view, 
                        astar_initializer_t& initializer);
         void run(bool iterate, unsigned long long iteration_number);
         void fill_shpath(std::list<lat_lon_t>& list) const;

         vertex_debug_t get_debug_vertex_by_id(vertex_id_t id, bool fwd_search);
         template<search_direction_e direction>
         lat_lon_t get_potential(point_t p);
         vertex_id_t get_cur_vertex_id_fwd() const;
         vertex_id_t get_cur_vertex_id_bkwd() const;
         
         vertex_id_t get_start_vertex_id() const;
         vertex_id_t get_finish_vertex_id() const;
         lat_lon_t get_start_lat() const;
         lat_lon_t get_start_lon() const;
         lat_lon_t get_finish_lat() const;
         lat_lon_t get_finish_lon() const;
         bool is_all_ended() const;
         
         alg_debug_info_ptr_t debug_info_;    
      private:
         vertex_id_t start_vertex_id_;
         vertex_id_t finish_vertex_id_;
         //Algorithm state
         vertex_id_t current_v_id_fwd_;
         vertex_id_t current_v_id_bkwd_;
         bool is_ended_fwd_;
         bool is_ended_bkwd_;
         
         alg_data_container_t<astar_vertex_data_t> vertex_data_fwd_;
         alg_data_container_t<astar_vertex_data_t> vertex_data_bkwd_;
         min_heap_t min_queue_fwd_; 
         min_heap_t min_queue_bkwd_;
         //end alg state

         graph_view_ptr_t view_;
         
         vertex_t const & get_vertex_by_id(vertex_id_t id) const;
         lat_lon_t potential_fwd(point_t p);
         lat_lon_t potential_bkwd(point_t p);
         vertex_id_t extract_min_fwd();
         vertex_id_t extract_min_bkwd();
         void new_vertex_fwd(vertex_id_t id, lat_lon_t distance, vertex_id_t pred_id); //pred_id - predecessor_id
         void new_vertex_bkwd(vertex_id_t id, lat_lon_t distance, vertex_id_t pred_id);
         void set_processed_fwd(vertex_id_t id);
         void set_processed_bkwd(vertex_id_t id);
         bool is_in_min_queue_fwd(vertex_id_t id);
         bool is_in_min_queue_bkwd(vertex_id_t id);
         bool is_processed_fwd(vertex_id_t id);
         bool is_processed_bkwd(vertex_id_t id);
         bool is_min_queue_empty_fwd();
         bool is_min_queue_empty_bkwd();
         lat_lon_t get_distance_fwd(vertex_id_t id);
         lat_lon_t get_distance_bkwd(vertex_id_t id);
         void update_vertex_fwd(vertex_id_t id, lat_lon_t dist, vertex_id_t id_pred);
         void update_vertex_bkwd(vertex_id_t id, lat_lon_t dist, vertex_id_t id_pred);
         
         void collect_stats_fwd();
         void collect_stats_bkwd();
         void process_current_adjacent_fwd();
         void process_current_adjacent_bkwd();
         void run_undirect(bool iterate, unsigned long long iteration_number);
         void run_bidirect(bool iterate, unsigned long long iteration_number);
         
         point_t start_p_;
         point_t finish_p_;
         
         alg_data_container_t<point_t> nearest_start_ps_; //points on edges, nearest to start point. 
                                                          //The points are nearest to start point too.
         alg_data_container_t<point_t> nearest_finish_ps_;


         lat_lon_t min_path_len_of_bidirect_search_;
         vertex_id_t sh_path_vert_fwd_;
         vertex_id_t sh_path_vert_bkwd_;
         
         friend struct astar_initializer_t;
      };
   }
}
